import fs from 'fs'
import os from 'os'
import path from 'path'
import net from 'net'
import http from 'http'
import mimetype from 'mimetype'
import express from 'express'
import expressHBS from 'express-handlebars'


let iCurrentWindow = {};

function fParseFolder(sPath) { 
  var aFiles = [];
  var aFolders = [];
  fs.readdirSync(sPath).forEach(function (sFile) {
    var oFile, sMimeType;
    if (sFile.substr(0, 1) !== ".") {
      oFile = fs.statSync(sPath + "/" + sFile);
      sMimeType = mimetype.lookup(sFile);
      var obj = { 
        "isFolder": !!oFile.isDirectory(),
        "mime": !!oFile.isDirectory() ? "folder" : (sMimeType ? sMimeType.split("/")[0] : "unknown"),
        "name": sFile,
        "href": sFile,
        "size": 0,
        "target": !!oFile.isDirectory() ? '' : " target='_blank' ",
        "time": {
          "raw": oFile.mtime,
          "human": ''
        }
      };

      if (!oFile.isDirectory()) {
        aFiles.push(obj);
      } else {
        aFolders.push(obj);
      }
    }
  });
  return aFolders.concat(aFiles);
};

function fCheckForAutoIndex(oRequest, oResponse, fNext) {
  var sPath;

  if (oRequest.url.substr(-1) === "/") {
    sPath = path.join(iCurrentWindow.mRootPath, decodeURIComponent(oRequest.url));
    // if (fs.existsSync(sPath + "/index.html") || fs.existsSync(sPath + "/index.htm")) {
    //   return fNext();
    // }

    oResponse.render("autoindex.hbs", {
      "files": fParseFolder(sPath),
      "hasParent": oRequest.url !== "/",
      "port": '',
      "ip": '',
      "root": '',
      "folder": decodeURIComponent(oRequest.url)
    });
  } else {
    fNext();
  }
};

function getIPAddress() {
  var ifaces = os.networkInterfaces();
  var ip = '';
  for (var dev in ifaces) {
    ifaces[dev].forEach(function (details) {
      if (ip === '' && details.family === 'IPv4' && !details.internal) {
        ip = details.address;
        return;
      }
    });
  }
  return ip || "127.0.0.1";
};

function emptyPort(opt, callback) {
  var customPort = opt.customPort ? opt.customPort : null;
  var startPort = opt.startPort || opt.port || 1;
  var maxPort = opt.maxPort || opt.port || 65535;
  var host = opt.host || 'localhost';

  var usedPorts = {};
  var usedPortCount = 0;

  var range = maxPort - startPort;

  var pickRandomPort = function () {
    if (usedPortCount >= range) {
      return null;
    }

    var port = startPort + parseInt(Math.random() * (range + 1));

    return usedPorts[port] ? pickRandomPort() : port;
  };

  var tryToConnect = function (port, callback) {
    var socket = new net.Socket();
    var server = new net.Server();

    socket.on('error', function (err) {
      server.on('error', function (err) {
        callback(err);
      });
      server.listen(port, host, function () {
        server.close();
        callback();
      });
    });
    socket.connect(port, host, function () {
      socket.end();
      callback('listened port');
    });
  };

  var iterator = function (next) {
    var pickedPort;
    // console.log('usedPorts:', usedPorts);
    if (customPort && !usedPorts[customPort]) {
      pickedPort = customPort;
    } else {
      pickedPort = pickRandomPort();
    }

    if (!pickedPort) {
      return callback('not found.');
    }

    tryToConnect(pickedPort, function (err) {
      // console.log(err);
      if (err) {
        usedPorts[pickedPort] = true;
        usedPortCount++;
        return iterator(next);
      }
      return callback(null, pickedPort);
    });
  };

  iterator();
};


function startServer(mRootPath, mPort, mIp, callback) {
  mIp = mIp ? mIp : getIPAddress();
  if (!mPort || !mIp || !mRootPath) {
    return;
  }

  console.log(mPort, mIp, mRootPath, __static);
  iCurrentWindow.mRootPath = mRootPath;
  iCurrentWindow.mPort = mPort;
  iCurrentWindow.mIp = mIp;
  iCurrentWindow.mUrl = 'http://' + mIp + ':' + mPort;

  let app = express();
  app.engine("hbs", expressHBS({ "extname": "hbs" }))
  app.set("view engine", "hbs")
  app.set("views", path.join(__static, '/views'))
  app.use(fCheckForAutoIndex)
  // .use(fServerLogging)
  app.use("/__dev", express.static(path.join(__static, '/autoindexes')))
  app.use(express.static(mRootPath))
  app.all("*", function (oRequest, oResponse) {
    var _ref, sExtension, sDirname;
    if (oRequest.url === "/favicon.ico") {
      return oResponse.status(404).send("404 Not found");
    }
    if (oRequest.url.indexOf(".") > -1) {
      sExtension = (_ref = oRequest.url.split("."))[_ref.length - 1];
      if (sExtension !== "html" && sExtension !== "htm") {
        return oResponse.redirect(oRequest.url + ".html");
      } else {
        sDirname = path.dirname(oRequest.url);
        oResponse.status(404).render("autoindex.hbs", {
          "error": true,
          "files": fParseFolder(path.join(mRootPath, sDirname)),
          "hasParent": sDirname !== "/",
          "port": mPort,
          "root": mRootPath.replace(os.homedir(), "~"),
          "folder": sDirname,
          "url": oRequest.url
        });
      }
    } else {
      return oResponse.redirect(oRequest.url + ".html");
    }
  });

  let server = http.createServer(app).listen(mPort, function () {
    iCurrentWindow.server = server;
    callback(iCurrentWindow);
  });

  server.on('error', function (err) {
    callback(new Error(err));
  });
}

/**
 * close the server
 * @param {*} callback 
 */
function closeServer(callback) {
  try {
    iCurrentWindow.server.close();
    iCurrentWindow = {};

    callback({});
  } catch (e) {
    callback(new Error(e));
  }
}


export default {
  startServer,
  closeServer,
  emptyPort
}